package keshe_01;

import java.awt.*;
import java.io.*;
import java.lang.*;
import java.util.*;

class CriticalOfReader//读者临界区
{
         private int m_critical;
         CriticalOfReader()
         {
                   m_critical=0;
         }
         public synchronized void enterCriticalSection()//进入临界区
         {
                   try
                   {
                    if(m_critical!=0)wait();
                    }catch (InterruptedException e) { }
             m_critical=1;
         }
         public synchronized void leaveCriticalSection()//离开临界区
         {
                   m_critical=0;
                   notify();
         }
}
class CriticalOfWriter//写者临界区
{
         private  int m_critical;
         CriticalOfWriter()
         {
                   m_critical=0;
         }
         public synchronized void enterCriticalSection()//进入临界区
         {
                   try
                   {
                      if(m_critical!=0)wait();
                    }catch (InterruptedException e) { }
             m_critical=1;
         }
         public synchronized void leaveCriticalSection()//离开临界区
         {
                   m_critical=0;
                   notify();
         }
}
class Reader_Writer_Thread extends Thread
{
         static final int PER_SEC_DELAY=1000;						//每秒运行数
         private static int m_ipriority;									//优先级别(1代表读者优先,2代表写者优先)
         private static CriticalOfWriter m_criticalOfWriter;	//写者临界区
         private static CriticalOfReader m_criticalOfReader;	//读者临界区
         private static int m_iNumOfWriter;							//写者总数
         private static int m_iNumOfReader;							//读者总数
         private char m_chEntity;											//线程类别
         private int m_iSerial;												//进程序号
         private double m_dDelay;										//延迟时间
         private double m_dPersist;										//操作持续时间
         static
         {
                   m_ipriority=0;
                   m_iNumOfWriter=0;
                   m_iNumOfReader=0;
                   m_criticalOfWriter=new CriticalOfWriter();
                   m_criticalOfReader=new CriticalOfReader();
         }
         Reader_Writer_Thread(char entity,int serial,double delay,double persist)//构造函数
         {
                   m_chEntity=entity;		//进程类型
                   m_iSerial=serial;		//进程序号
                   m_dDelay=delay;		//延迟时间
                   m_dPersist=persist;	//操作持续时间
         }
         public boolean setpriority(int priority)//设置优先级(1代表读者优先,2代表写者优先)
         {
                   if(priority==1||priority==2){m_ipriority=priority;return true;}
                   return false;
         }
         public void run()//线程主运行
         {
                   //区别写者与读者线程
                   if(m_chEntity=='r')reader_run();
                   else if(m_chEntity=='w')writer_run();
         }
         public void reader_run()//读者线程运行函数
         {
                   try
                   {
                            Thread.sleep((long)m_dDelay*PER_SEC_DELAY);
                   }catch(InterruptedException e){}
                   Date temp=new Date();
                   System.out.print(Integer.toString(temp.getMinutes())+":"
                                         +Integer.toString(temp.getSeconds())+" ");
                   System.out.println("读进程 "+m_iSerial+" 发送读请求.");
                   incNumOfReader();  //读进程进入队列
                   try
                   {
                            sleep((long)m_dPersist*PER_SEC_DELAY);
                   }catch(InterruptedException e){}
                   decNumOfReader(); //释放互斥信号
         }
         public void writer_run()//写者线程线程运行函数
         {
                   try
                   {
                            Thread.sleep((long)m_dDelay*PER_SEC_DELAY);
                   }catch(InterruptedException e){}
                   Date temp=new Date();
                   System.out.print(Integer.toString(temp.getMinutes())+":"
                                         +Integer.toString(temp.getSeconds())+" ");
                   System.out.println("写进程 "+m_iSerial+" 发送写请求");
                   incNumOfWriter();//写进程进入队列
                   try
                   {
                            sleep((long)m_dPersist*PER_SEC_DELAY);
                   }catch(InterruptedException e){}
                   decNumOfWriter();//释放互斥信号
         }
         public synchronized void incNumOfReader()//互斥
         {
                  
                   //写者优先时,先进入读者临界区,申请进程优先互斥
                   if(m_ipriority==2)m_criticalOfReader.enterCriticalSection();
                   //如果是第一个读者,则等待写者写完
                   m_iNumOfReader++;   //读者队列+1
                   if(m_iNumOfReader==1)m_criticalOfWriter.enterCriticalSection();
                  
                   if(m_ipriority==2)m_criticalOfReader.leaveCriticalSection();//让其他读者进(不占地方)
                   Date temp=new Date();
                   System.out.print(Integer.toString(temp.getMinutes())+":"
                                         +Integer.toString(temp.getSeconds())+" ");
                   System.out.println("读进程 "+m_iSerial+" 开始读文件了！");
         }
         public synchronized void decNumOfReader()//互斥
         {
                   m_iNumOfReader--; //读者队列-1
                   Date temp=new Date();
                   System.out.print(Integer.toString(temp.getMinutes())+":"
                                         +Integer.toString(temp.getSeconds())+" ");
                   System.out.println("读进程 "+m_iSerial+" 完成了读操作！");
                   if(m_iNumOfReader==0)m_criticalOfWriter.leaveCriticalSection();//都读完了,唤醒写者
         }
         public synchronized void incNumOfWriter()//互斥
         {
                   m_iNumOfWriter++;
                   //若是写者优先,第一个写者需等待读者写完
                   if(m_ipriority==2&&m_iNumOfWriter==1)m_criticalOfReader.enterCriticalSection();
                   m_criticalOfWriter.enterCriticalSection();//进入写者临界区
                   Date temp=new Date();
                   System.out.print(Integer.toString(temp.getMinutes())+":"
                                         +Integer.toString(temp.getSeconds())+" ");
                   System.out.println("写进程 "+m_iSerial+" 开始写操作了！");
         }
         public synchronized void decNumOfWriter()//互斥
         {
                   m_iNumOfWriter--;
                   Date temp=new Date();
                   System.out.print(Integer.toString(temp.getMinutes())+":"
                                         +Integer.toString(temp.getSeconds())+" ");
                   System.out.println("写进程 "+m_iSerial+"完成了写操作！");
                   m_criticalOfWriter.leaveCriticalSection();//唤醒等待者(读者写者都有可能)
                   if(m_iNumOfWriter==0&&m_ipriority==2)m_criticalOfReader.leaveCriticalSection();
                   //最后一个读者,唤醒写者,让权给写者
         }
}

public class Rwproblem
{
         static final int MAX_THREAD_NUM=64;  //默认最大进程数量
         public static void main(String args[])
         {
             char test='0';
             do
             {            
                 System.out.println();
                 System.out.println("----------主菜单----------");
                 System.out.println("     1:读者优先.");
                 System.out.println("     2:写者优先.");
                 System.out.println("     3:结束程序.");
                 try
                 {
                    test=(char)System.in.read();
                    System.in.read();
                    }catch(IOException e){}
              }while(test!='3'&&test!='1'&&test!='2');
                        if(test=='3')return;
                              Reader_Writer_Thread [] m_thread;
                              m_thread = new Reader_Writer_Thread[MAX_THREAD_NUM];
                              m_thread[0] = new Reader_Writer_Thread('r',1,3,5);//读进程1
                              m_thread[1] = new Reader_Writer_Thread('w',2,4,5);//写进程2
                              m_thread[2] = new Reader_Writer_Thread('r',3,5,2);	//读进程3
                              m_thread[3] = new Reader_Writer_Thread('r',4,6,5);//读进程4
                              m_thread[4] = new Reader_Writer_Thread('w',5,5,3);//写进程5
                              if(test=='2')
                              {
                                       m_thread[0].setpriority(2);
                                       System.out.println("   进入写者优先");
                              }
                              else System.out.println("     进入读者优先");
                              m_thread[0].start();
							  m_thread[1].start();
                              m_thread[2].start();
                              m_thread[3].start();
                              m_thread[4].start();
          }
}